package com.micro.ai.commons.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * JWT工具类（统一版本）
 * 整合了Gateway和Auth的JWT功能
 * 支持配置动态刷新（@RefreshScope）
 * 
 * @author micro-ai
 * @since 0.0.1
 * @version 1.1 添加@RefreshScope支持动态配置
 */
@Slf4j
@Component
@RefreshScope
public class JwtUtils {

    @Value("${jwt.secret:micro-ai-secret-key-2024-please-change-in-production}")
    private String secret;

    @Value("${jwt.access-token-expiration:7200}")
    private Long accessTokenExpiration;

    @Value("${jwt.refresh-token-expiration:604800}")
    private Long refreshTokenExpiration;

    @Value("${jwt.issuer:micro-ai}")
    private String issuer;

    /**
     * 生成访问令牌（完整版本）
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @param username 用户名
     * @param roles 角色列表
     * @param permissions 权限列表
     * @return JWT令牌
     */
    public String generateAccessToken(String userId, String tenantId, String username, 
                                      List<String> roles, List<String> permissions) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + accessTokenExpiration * 1000);

        return Jwts.builder()
                .setSubject(userId)
                .claim("tenantId", tenantId)
                .claim("username", username)
                .claim("roles", roles)
                .claim("permissions", permissions)
                .setIssuer(issuer)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(getSecretKey(), io.jsonwebtoken.SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 生成访问令牌（简化版本）
     * 
     * @param userId 用户ID
     * @param username 用户名
     * @param claims 附加声明
     * @return JWT令牌
     */
    public String generateToken(String userId, String username, Map<String, Object> claims) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + accessTokenExpiration * 1000);

        return Jwts.builder()
                .setSubject(userId)
                .claim("username", username)
                .addClaims(claims)
                .setIssuer(issuer)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(getSecretKey(), io.jsonwebtoken.SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 生成访问令牌（最简版本）
     * 
     * @param userId 用户ID
     * @param username 用户名
     * @return JWT令牌
     */
    public String generateToken(String userId, String username) {
        return generateToken(userId, username, Map.of());
    }

    /**
     * 生成刷新令牌
     * 
     * @param userId 用户ID
     * @return 刷新令牌
     */
    public String generateRefreshToken(String userId) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + refreshTokenExpiration * 1000);

        return Jwts.builder()
                .setSubject(userId)
                .setIssuer(issuer)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(getSecretKey(), io.jsonwebtoken.SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 验证JWT令牌
     * 
     * @param token JWT令牌
     * @return Claims对象，如果验证失败返回null
     */
    public Claims validateToken(String token) {
        try {
            SecretKey secretKey = getSecretKey();
            log.info("=== JWT 验证调试 ===");
            log.info("Token header: {}", extractHeader(token));
            log.info("使用密钥: {}", secret);
            log.info("Secret key bytes length: {}", secret.getBytes().length);
            log.info("Hashed key encoded length: {}", secretKey.getEncoded().length);
            
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(secretKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            
            log.info("✅ JWT 验证成功");
            log.info("用户ID: {}", claims.getSubject());
            return claims;
        } catch (Exception e) {
            log.error("❌ JWT令牌验证失败: {}", e.getMessage());
            log.error("密钥: {}", secret);
            log.error("Token 算法可能不匹配或密钥不一致");
            log.error("请确保使用相同密钥生成的 Token");
            return null;
        }
    }
    
    /**
     * 提取JWT header用于调试
     */
    private String extractHeader(String token) {
        try {
            String[] parts = token.split("\\.");
            if (parts.length >= 1) {
                String headerJson = new String(java.util.Base64.getUrlDecoder().decode(parts[0]));
                return headerJson;
            }
        } catch (Exception e) {
            // ignore
        }
        return "无法解析";
    }

    /**
     * 从令牌中获取用户ID
     * 
     * @param token JWT令牌
     * @return 用户ID
     */
    public String getUserId(String token) {
        Claims claims = validateToken(token);
        return claims != null ? claims.getSubject() : null;
    }

    /**
     * 从令牌中获取租户ID
     * 
     * @param token JWT令牌
     * @return 租户ID
     */
    public String getTenantId(String token) {
        Claims claims = validateToken(token);
        return claims != null ? claims.get("tenantId", String.class) : null;
    }

    /**
     * 从令牌中获取用户名
     * 
     * @param token JWT令牌
     * @return 用户名
     */
    public String getUsername(String token) {
        Claims claims = validateToken(token);
        return claims != null ? claims.get("username", String.class) : null;
    }

    /**
     * 从令牌中获取角色列表
     * 
     * @param token JWT令牌
     * @return 角色列表
     */
    @SuppressWarnings("unchecked")
    public List<String> getRoles(String token) {
        Claims claims = validateToken(token);
        return claims != null ? claims.get("roles", List.class) : List.of();
    }

    /**
     * 从令牌中获取权限列表
     * 
     * @param token JWT令牌
     * @return 权限列表
     */
    @SuppressWarnings("unchecked")
    public List<String> getPermissions(String token) {
        Claims claims = validateToken(token);
        return claims != null ? claims.get("permissions", List.class) : List.of();
    }

    /**
     * 检查令牌是否过期
     * 
     * @param token JWT令牌
     * @return 是否过期
     */
    public boolean isTokenExpired(String token) {
        Claims claims = validateToken(token);
        if (claims == null) {
            return true;
        }
        return claims.getExpiration().before(new Date());
    }

    /**
     * 刷新令牌
     * 
     * @param token 旧令牌
     * @return 新令牌
     */
    public String refreshToken(String token) {
        Claims claims = validateToken(token);
        if (claims == null) {
            return null;
        }
        
        String userId = claims.getSubject();
        String username = claims.get("username", String.class);
        
        // 复制原有的声明，但移除标准声明
        Map<String, Object> newClaims = Map.of(
            "tenantId", claims.getOrDefault("tenantId", ""),
            "roles", claims.getOrDefault("roles", List.of()),
            "permissions", claims.getOrDefault("permissions", List.of())
        );
        
        return generateToken(userId, username, newClaims);
    }

    /**
     * 从令牌中获取Claims
     * 
     * @param token JWT令牌
     * @return Claims对象
     */
    public Claims getClaims(String token) {
        return validateToken(token);
    }

    /**
     * 获取访问令牌过期时间（秒）
     * 
     * @return 过期时间
     */
    public Long getAccessTokenExpiration() {
        return accessTokenExpiration;
    }

    /**
     * 获取刷新令牌过期时间（秒）
     * 
     * @return 过期时间
     */
    public Long getRefreshTokenExpiration() {
        return refreshTokenExpiration;
    }

    /**
     * 获取令牌过期时间（秒）- 兼容方法
     * 
     * @return 过期时间
     */
    public Long getExpiration() {
        return accessTokenExpiration;
    }

    /**
     * 获取密钥
     * 
     * @return 密钥
     */
    private SecretKey getSecretKey() {
        // 对于 HS256，密钥长度至少需要 256 位（32 字节）
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        
        try {
            // 使用 SHA-256 哈希确保密钥长度满足要求
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashedKey = digest.digest(keyBytes);
            
            return Keys.hmacShaKeyFor(hashedKey);
        } catch (Exception e) {
            log.error("生成密钥失败: {}", e.getMessage());
            // 降级方案：直接使用原始密钥
            return Keys.hmacShaKeyFor(keyBytes);
        }
    }
}

